package util

import (
	"gitverse.ru/synapse/kubelatte/pkg/observability/logs"
	v1 "k8s.io/api/core/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/labels"
	"strings"
)

type NamespaceSelector struct {
	LabelSelector metav1.LabelSelector `json:"labelSelector,omitempty"`
	Include       []string             `json:"include,omitempty"`
	Exclude       []string             `json:"exclude,omitempty"`
}

func (s *NamespaceSelector) MatchNamespace(namespace *v1.Namespace) bool {
	labelMatched := false
	if s.LabelSelector.MatchLabels != nil || s.LabelSelector.MatchExpressions != nil {
		if ok, _ := MatchLabels(namespace, &s.LabelSelector); ok {
			labelMatched = true
		}
	}
	if len(s.Include) == 0 && len(s.Exclude) == 0 {
		return labelMatched
	} else {
		return s.MatchNamespaceName(namespace.GetName())
	}
}

func (s *NamespaceSelector) MatchNamespaceName(nsName string) bool {
	included := MatchWithPatternArray(nsName, s.Include)
	excluded := MatchWithPatternArray(nsName, s.Exclude)
	logs.Debugf("MatchNamespaceName check ns %s result %T", nsName, included && !excluded)
	return included && !excluded
}

func MatchLabels(obj metav1.Object, labelSelector *metav1.LabelSelector) (bool, error) {
	selector, err := metav1.LabelSelectorAsSelector(labelSelector)
	if err != nil {
		return false, err
	}
	labelsMap := obj.GetLabels()
	labelsSet := labels.Set(labelsMap)
	matched := selector.Matches(labelsSet)
	return matched, nil
}

func MatchWithPatternArray(value string, patternArray []string) bool {
	for _, pattern := range patternArray {
		if MatchPattern(pattern, value) {
			return true
		}
	}
	return false
}

func MatchPattern(pattern, value string) bool {
	pattern = strings.TrimSpace(pattern)
	if pattern == "" {
		return true
	} else if pattern == "*" {
		return true
	} else if pattern == "-" && value == "" {
		return true
	} else if strings.HasSuffix(pattern, "*") {
		return strings.HasPrefix(value, strings.TrimRight(pattern, "*"))
	} else if pattern == value {
		return true
	} else if strings.Contains(pattern, ",") {
		patterns := SplitRule(pattern)
		return MatchWithPatternArray(value, patterns)
	} else {
		return false
	}
}

func SplitRule(rules string) []string {
	result := []string{}
	slice := strings.Split(rules, ",")
	for _, s := range slice {
		rule := strings.TrimSpace(s)
		result = append(result, rule)
	}
	return result
}
